Introduction
The OPC UA application manifest contains the application registration information together with data related to PKI administration, such as paths to the certificate stores used.
The information contained in the OPC UA application manifest can roughly be divided into three areas:
- Information that identifies or otherwise integrates the application in the OPC UA ecosystem, such as application URI, application type, application name, and product URI.
- Information needed to create the application instance certificate, such as the certificate subject name or its parts. Note that the certificate also contains some of the information described above, such as the application URI.
- Information that allows the OPC UA application to execute and be administered in the operating system environment, such as location of the certificate stores it uses.
One important piece of information is the subject name of the application instance certificate. The component uses the subject name to locate the instance certificate in the certificate store, and if it is not found, it attempts to create a new instance certificate, and store it with the subject name. The default subject name is created automatically, based on the description (title) of the application assembly, or (if the preceding yields a name that is too generic, such as ‘mscorlib’ in many hosted scenarios) from other sources of information, such as the executable’s FileVersionInfo, or a main module name.
The application URI can be specified explicitly, or (if left empty) the component will determine it automatically, using the ApplicationUriTemplateString Property. See OPC UA Application URI Derivation for the template syntax, and more details about how the application URI is determined.
If you want to use a specific subject name for your application instance certificate, set the EasyUAApplication.ApplicationParameters.ApplicationManifest.InstanceCertificateSubject Property accordingly.
If you leave the subject name empty, QuickOPC will determine the subject name automatically from other information available. For example, when any of the properties below is not empty, QuickOPC will include it in the subject name:
Other parameters that influence the application certificate creation are e.g. EasyUAApplication.ApplicationParameters.ApplicationManifest.ApplicationName, ApplicationUriString, and ProductUriString Property.
Effective Application Manifest
The full OPC UA application manifest contains a considerable amount of information. On one hand, all this information is critical to proper functioning of the OPC UA application itself, and it the OPC UA ecosystem. On the other hand, it would be cumbersome having to fill it in in its entirety for each new application. For this reason, QuickOPC uses a process in which it automatically acquires the information needed in the OPC UA application manifest from various sources, and by combining the information in a prescribed way, it finally determines the effective application manifest, which is the OPC UA application manifest that will actually be used for OPC UA operations performed by QuickOPC.
The effective application manifest is made first by composing the application manifest information from several sources, and then by resolving certain parts inside the manifest. The details of the composition and resolution processes are described further below.
Application Manifest Composition
The composition of the OPC UA application manifest is done using the following steps, in the specified order:
- An OPC UA automatic application manifest is determined (see further below).
- If the OPC UA application manifest attribute (see further below) is available, information from it overrides the information gathered so far. By default, unless you add the OPC UA application manifest attribute to your project, this step does nothing.
- Information from the application manifest in the application parameters (EasyUAClient.SharedParameters.EngineParameters.ApplicationParameters.ApplicationManifest ) then overrides the information gathered so far. By default, unless you set something in the application parameters explicitly from your code, this step does nothing, because the manifest information in application parameters is empty.
You can see that in the default state, only the first step (OPC UA automatic application manifest) provides the actual information; the remaining steps do nothing. If you want to modify some or all of the application provided by the automatic application manifest, you can use the OPC UA application manifest attribute to change it (this is the recommended way), or you can modify the information by writing code that changes it in the application parameters.
The reason why using the OPC UA application manifest attribute is preferred over setting the parameters from the code is that in many cases, application manifest information is needed outside of the application itself. For example, it might be needed for external administration tools. Such tools are able to read the OPC UA application manifest attribute from the application, but will not be able to see into the code and determine which values your application is setting to the application parameters.
The information in the OPC UA application manifest consists mostly of strings. Inthe composition process, a non-empty string in the application manifest that is being added to the composition overrides the existing information. An empty string leaves the information as it was. A string equal to "#" sets the information back to an empty string (this is rarely needed). For example, if the automatic application manifest determines the application name as "My Application", and you do not feel that this is the right name, you can set a non-empty application name in the OPC UA application manifest attribute, e.g. "Process Monitoring", and that will become the effective name.
Application Manifest Resolution
After the composed application manifest is computed using the process described above, QuickOPC resolves some information contained in it. Specifically, the special folder names that may be contained in certificate store paths (such as "LocalFolder") are resolved to absolute paths. The resolution process is important to assure that the certificate store paths do not change over time. Also, if/when the security configuration is exported from the application, it needs to be stripped off unnecessary context so that it is usable "as is", standalone.
Automatic Application Manifest
The automatic application manifest attempts to provide reasonable information, either by using some common defaults, or by gathering the data about the application itself. Specifically:
- The application name is taken from the application assembly title attribute, or file description or file name of from the application version info, or from the application module name.
- The application URI is constructed from the template string (ApplicationUriTemplateString Property), using the process described in OPC UA Application URI Derivation.
- The product URI constructed as URN, containing the product name from the application assembly product attribute, from the application version info, or the application module name.
- All store paths have common defaults (with use of special symbols that adapt them automatically to particular operating system installation).
- The organization name is taken from the application assembly company attribute, or company name from the application version info.
Application Manifest Attribute
Using the application manifest attribute is the preferred way to specify the OPC UA Application Manifest information, if it differs from what is provided by the automatic application manifest functionality. This method is only available in .NET applications.
The application manifest attribute is represented by the UAApplicationManifestAttribute Class. It contains properties for all information contained in the application manifest. As explained above in the "Application Manifest Composition" chapter, the application manifest attribute is evaluated after the automatic manifest attribute values are obtained. This means that you can only fill in the properties that you want to have changed from what is provided by the automatic application manifest functionality.
The application manifest attribute needs to be applied to the application assembly. The application assembly is usually the "main" assembly of you project. More precisely, it is:
Example syntax:
[assembly: UAApplicationManifest(OrganizationName="MyCompany", CountryName="US")]
<Assembly: UAApplicationManifest(OrganizationName:="MyCompany", CountryName:="US")>
Application Manifest in Application Parameters
You can also manipulate the application manifets information directly from your code, in the application parameters object. As explained above, this method is not preferred, and should only be used if you cannot use the automatic application manifest, possibly in combination with the application manifest attribute.
.NET
// This example demonstrates how to set the application name for the client certificate.
using System;
using OpcLabs.BaseLib.Instrumentation;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.Application;
using OpcLabs.EasyOpc.UA.OperationModel;
namespace UADocExamples._UAApplicationManifest
{
class ApplicationName
{
public static void Main1()
{
UAEndpointDescriptor endpointDescriptor =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
// or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
// or "https://opcua.demo-this.com:51212/UA/SampleServer/"
// Hook static events
EasyUAClient.LogEntry += EasyUAClientOnLogEntry;
try
{
// Set the application name, which determines the subject of the client certificate.
// Note that this only works once in each host process.
EasyUAApplication.Instance.ApplicationParameters.ApplicationManifest.ApplicationName =
"QuickOPC - CSharp example application";
// Do something - invoke an OPC read, to trigger some loggable entries.
var client = new EasyUAClient();
try
{
client.ReadValue(endpointDescriptor, "nsu=http://test.org/UA/Data/ ;i=10853");
}
catch (UAException uaException)
{
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
}
// The certificate will be located or created in a directory similar to:
// C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
// and its subject will be as given by the application name.
Console.WriteLine("Processing log entry events for 10 seconds...");
System.Threading.Thread.Sleep(10 * 1000);
Console.WriteLine("Finished.");
}
finally
{
// Unhook static events
EasyUAClient.LogEntry -= EasyUAClientOnLogEntry;
}
}
// Event handler for the LogEntry event.
// Print the loggable entry containing client certificate parameters.
private static void EasyUAClientOnLogEntry(object sender, LogEntryEventArgs logEntryEventArgs)
{
if (logEntryEventArgs.EventId == 161)
Console.WriteLine(logEntryEventArgs);
}
}
}
# This example demonstrates how to set the application name for the client certificate.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import time
# Import .NET namespaces.
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.Application import *
from OpcLabs.EasyOpc.UA.OperationModel import *
# Event handler for the LogEntry event.
# Print the loggable entry containing client certificate parameters.
def onLogEntry(sender, logEntryEventArgs):
if logEntryEventArgs.EventId == 161:
print(logEntryEventArgs)
endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'
# Hook static events.
EasyUAClient.LogEntry += onLogEntry
try:
# Set the application name, which determines the subject of the client certificate.
# Note that this only works once in each host process.
EasyUAApplication.Instance.ApplicationParameters.ApplicationManifest.ApplicationName = \
'QuickOPC - Python (.NET) example application'
# Do something - invoke an OPC read, to trigger some loggable entries.
client = EasyUAClient()
try:
value = IEasyUAClientExtension.ReadValue(client,
endpointDescriptor,
UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10853'))
except UAException as uaException:
print('*** Failure: ' + uaException.GetBaseException().Message)
# The certificate will be located or created in a directory similar to:
# C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
# and its subject will be as given by the application name.
print('Processing log entry events for 10 seconds...')
time.sleep(10)
print('Finished.')
finally:
# Unhook static events.
EasyUAClient.LogEntry -= onLogEntry
' This example demonstrates how to set the application name for the client certificate.
Imports OpcLabs.BaseLib.Instrumentation
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.Application
Imports OpcLabs.EasyOpc.UA.OperationModel
Namespace _UAApplicationManifest
Friend Class ApplicationName
Public Shared Sub Main1()
Dim endpointDescriptor As UAEndpointDescriptor =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
' or "https://opcua.demo-this.com:51212/UA/SampleServer/"
' Hook static events
AddHandler EasyUAClient.LogEntry, AddressOf EasyUAClientOnLogEntry
Try
' Set the application name, which determines the subject of the client certificate.
' Note that this only works once in each host process.
EasyUAApplication.Instance.ApplicationParameters.ApplicationManifest.ApplicationName =
"QuickOPC - VBNet example application"
' Do something - invoke an OPC read, to trigger some loggable entries.
Dim client = New EasyUAClient()
Try
client.ReadValue(endpointDescriptor, "nsu=http://test.org/UA/Data/ ;i=10853")
Catch uaException As UAException
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
Exit Sub
End Try
' The certificate will be located or created in a directory similar to:
' C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
' and its subject will be as given by the application name.
Console.WriteLine("Processing log entry events for 10 seconds...")
Threading.Thread.Sleep(10 * 1000)
Console.WriteLine("Finished.")
Finally
' Unhook static events
RemoveHandler EasyUAClient.LogEntry, AddressOf EasyUAClientOnLogEntry
End Try
End Sub
' Event handler for the LogEntry event.
' Print the loggable entry containing client certificate parameters.
Private Shared Sub EasyUAClientOnLogEntry(ByVal sender As Object, ByVal logEntryEventArgs As LogEntryEventArgs)
If (logEntryEventArgs.EventId = 161) Then
Console.WriteLine(logEntryEventArgs)
End If
End Sub
End Class
End Namespace
COM
// This example demonstrates how to set the application name for the client certificate.
type
TClientManagementEventHandlers103 = class
procedure OnLogEntry(
ASender: TObject;
sender: OleVariant;
const eventArgs: _LogEntryEventArgs);
end;
// Event handler for the LogEntry event.
// Print the loggable entry containing client certificate parameters.
procedure TClientManagementEventHandlers103.OnLogEntry(
ASender: TObject;
sender: OleVariant;
const eventArgs: _LogEntryEventArgs);
begin
if eventArgs.EventId = 161 then
WriteLn(eventArgs.ToString);
end;
class procedure ApplicationName.Main;
var
Application: TEasyUAApplication;
Client: OpcLabs_EasyOpcUA_TLB._EasyUAClient;
ClientManagement: TEasyUAClientManagement;
ClientManagementEventHandlers: TClientManagementEventHandlers103;
Value: OleVariant;
begin
// The configuration object allows access to static behavior - here, the
// shared LogEntry event.
ClientManagement := TEasyUAClientManagement.Create(nil);
ClientManagementEventHandlers := TClientManagementEventHandlers103.Create;
ClientManagement.OnLogEntry := ClientManagementEventHandlers.OnLogEntry;
ClientManagement.Connect;
// Obtain the application interface.
Application := TEasyUAApplication.Create(nil);
try
// Set the application name, which determines the subject of the client certificate.
// Note that this only works once in each host process.
Application.ApplicationParameters.ApplicationManifest.ApplicationName :=
'QuickOPC - Delphi example application';
// Do something - invoke an OPC read, to trigger some loggable entries.
Client := CoEasyUAClient.Create;
try
Value := Client.ReadValue(
//'http://opcua.demo-this.com:51211/UA/SampleServer',
//'https://opcua.demo-this.com:51212/UA/SampleServer/',
'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer',
'nsu=http://test.org/UA/Data/ ;i=10853');
except
on E: EOleException do
begin
WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
end;
end;
// The certificate will be located or created in a directory similar to:
// C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
// and its subject will be as given by the application name.
WriteLn('Processing log entry events for 10 seconds...');
PumpSleep(10*1000);
WriteLn('Finished...');
finally
FreeAndNil(Application);
FreeAndNil(ClientManagement);
FreeAndNil(ClientManagementEventHandlers);
end;
end;
// This example demonstrates how to set the application name for the client certificate.
class ClientManagementEvents {
// Event handler for the LogEntry event.
// Print the loggable entry containing client certificate parameters.
function LogEntry($Sender, $E)
{
if ($E->EventId == 161)
printf("%s\n", $E);
}
}
// The management object allows access to static behavior - here, the
// shared LogEntry event.
$ClientManagement = new COM("OpcLabs.EasyOpc.UA.EasyUAClientManagement");
$ClientManagementEvents = new ClientManagementEvents();
com_event_sink($ClientManagement, $ClientManagementEvents, "DEasyUAClientManagementEvents");
// Obtain the application interface.
$Application = new COM("OpcLabs.EasyOpc.UA.Application.EasyUAApplication");
// Set the application name, which determines the subject of the client certificate.
// Note that this only works once in each host process.
$Application->ApplicationParameters->ApplicationManifest->ApplicationName = "QuickOPC - PHP example application";
// Do something - invoke an OPC read, to trigger some loggable entries.
$Client = new COM("OpcLabs.EasyOpc.UA.EasyUAClient");
try
{
$value = $Client->ReadValue(
//"http://opcua.demo-this.com:51211/UA/SampleServer",
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer",
"nsu=http://test.org/UA/Data/ ;i=10853");
}
catch (com_exception $e)
{
printf("*** Failure: %s\n", $e->getMessage());
}
// The certificate will be located or created in a directory similar to:
// C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
// and its subject will be as given by the application name.
printf("Processing log entry events for 10 seconds...");
$startTime = time(); do { com_message_pump(1000); } while (time() < $startTime + 10);
printf("Finished.\n");
Rem This example demonstrates how to set the application name for the client certificate.
Private Sub ApplicationName_Main_Command_Click()
OutputText = ""
' Obtain the application interface
Dim Application As New EasyUAApplication
' Set the application name, which determines the subject of the client certificate.
' Note that this only works once in each host process.
Application.ApplicationParameters.ApplicationManifest.applicationName = "QuickOPC - VB6 example application"
' Do something - invoke an OPC read, to trigger some loggable entries.
Dim client As New EasyUAClient
On Error Resume Next
Dim value As Variant
value = client.ReadValue("opc.tcp://opcua.demo-this.com:51210/UA/SampleServer", "nsu=http://test.org/UA/Data/ ;i=10853")
If Err.Number <> 0 Then
OutputText = OutputText & "*** Failure: " & Err.Source & ": " & Err.Description & vbCrLf
Exit Sub
End If
On Error GoTo 0
' The certificate will be located or created in a directory similar to:
' C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\certs
' and its subject will be as given by the application name.
OutputText = OutputText & "Processing log entry events for 10 seconds..." & vbCrLf
Pause 10000
Set Application = Nothing
OutputText = OutputText & "Finished..." & vbCrLf
End Sub
' Event handler for the LogEntry event. It simply prints out the event.
Private Sub ClientManagement1_LogEntry(ByVal sender As Variant, ByVal eventArgs As OpcLabs_BaseLib.LogEntryEventArgs)
If eventArgs.eventId = 161 Then
OutputText = OutputText & eventArgs & vbCrLf
End If
End Sub
Rem This example demonstrates how to set the application name for the client certificate.
Option Explicit
' The management object allows access to static behavior.
WScript.Echo "Obtaining the client management object..."
Dim ClientManagement: Set ClientManagement = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClientManagement")
WScript.ConnectObject ClientManagement, "ClientManagement_"
WScript.Echo "Obtaining the application interface..."
Dim Application: Set Application = CreateObject("OpcLabs.EasyOpc.UA.Application.EasyUAApplication")
' Set the application name, which determines the subject of the client certificate.
' Note that this only works once in each host process.
WScript.Echo "Setting the application name..."
Application.ApplicationParameters.ApplicationManifest.ApplicationName = "QuickOPC - VBScript example application"
WScript.Echo "Creating a client object..."
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")
' Do something - invoke an OPC read, to trigger some loggable entries.
WScript.Echo "Reading a value..."
On Error Resume Next
Dim value: value = Client.ReadValue("opc.tcp://opcua.demo-this.com:51210/UA/SampleServer", "nsu=http://test.org/UA/Data/ ;i=10853")
If Err.Number <> 0 Then
WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
WScript.Quit
End If
On Error Goto 0
' The certificate will be located or created in a directory similar to:
' C:\Users\All Users\OPC Foundation\CertificateStores\UA Applications\certs\
' and its subject will be as given by the application name.
WScript.Echo "Processing log entry events for 10 seconds..."
WScript.Sleep 10*1000
WScript.Echo "Finished."
' Event handler for the LogEntry event.
' Print the loggable entry containing client certificate parameters.
Sub ClientManagement_LogEntry(Sender, e)
If e.EventId = 161 Then WScript.Echo e
End Sub
See Also